from django.shortcuts import render

# Create your views here.

from lib.share import BaseRequestHandle
from main.models import User,Notice,News,Paper,Config,TSRelation,\
    ThumbupOrCancel,WF_Design,WF_Design_STEP,WF_Design_DataMgr
from django.contrib.auth import authenticate,login,logout
from lib.share import JR
from lib.share import BaseRequestHandle
from cofing.settings import UPLOAD_DIR
from datetime import datetime
from random import randint
import json,traceback
from django.db import transaction



class SignHandle(BaseRequestHandle):
    def __init__(self):
        self.action_table = {
            'signin':self.signin,
            'signout':self.signout
        }

    @staticmethod
    def signin(request):
        username = request.pd.get('username')
        password = request.pd.get('password')

        user = authenticate(username=username,password=password)

        if user is None:
            return JR({'ret': 2, 'msg': '用户名或密码错误'})

        if not user.is_active:
            return JR({'ret': 0, 'msg': '用户已经被禁用'})

        login(request,user)

        request.session['usertype'] = user.usertype
        request.session['userid'] = user.id

        return JR({
                    "ret": 0,
                    "usertype":user.usertype,
                    "userid":user.id,
                    "realname":user.realname,
                })

    @staticmethod
    def signout(request):
        logout(request)
        return JR({"ret": 0})

class AccountHandle(BaseRequestHandle):
    def __init__(self):
        self.action_table = {
            'listbypage':self.listbypage,
            'addone':self.addone,
            'modifyone':self.modifyone,
            'deleteone':self.deleteone
        }

    @BaseRequestHandle.admin_required
    def handle(self,request):
        return super().handle(request)

    @staticmethod
    def listbypage(request):
        pagesize = request.pd.get('pagesize')
        pagenum = request.pd.get('pagenum')
        keywords = request.pd.get('keywords')

        ret = User.listbypage(pagesize,pagenum,keywords)

        return JR(ret)

    @staticmethod
    def addone(request):
        data = request.pd.get('data')
        ret = User.addone(data)
        return JR(ret)

    @staticmethod
    def modifyone(request):
        oid = request.pd.get('id')
        newdata = request.pd.get('newdata')

        ret = User.modifyone(oid,newdata)

        return JR(ret)

    @staticmethod
    def deleteone(request):
        oid = request.pd.get('id')
        ret = User.deleteone(oid)

        return JR(ret)

class UploadHandler:
    def handle(self,request):
        uploadFile  = request.FILES['upload1']

        filetype = uploadFile.name.split('.')[-1]
        if filetype not in ['jpg','png']:
            return JR({'ret':430, 'msg':'只能上传 jpg png 文件'})

        if uploadFile.size > 10*1024*1024:
            return JR({'ret':431, 'msg':'文件太大'})

        suffix = datetime.now().strftime('%Y%m%d%H%M%S_') +  str(randint(0,999999))
        filename = f'{request.user.id}_{suffix}.{filetype}'

        # 写入文件到静态文件访问区
        with open(f'{UPLOAD_DIR}/{filename}','wb') as f:
            # 读取上传文件数据
            bytes = uploadFile.read()
            # 写入文件
            f.write(bytes)

        return JR({'ret':0,'url':f'/upload_byhy/{filename}'})

class ArticleHandle(BaseRequestHandle):
    def __init__(self):
        self.action_table = {
            'listbypage':self.listbypage,
            'listbypage_allstate':self.listbypage_allstate,
            'getone':self.getone,
            'addone':self.addone,
            'modifyone':self.modifyone,
            'banone':self.banone,
            'publishone':self.publishone,
            'deleteone':self.deleteone
        }


    def listbypage(self,request):
        pagesize = request.pd.get('pagesize')
        pagenum = request.pd.get('pagenum')
        keywords = request.pd.get('keywords')
        withoutcontent = request.pd.get('withoutcontent')

        withoutContent = False

        if withoutcontent == True:
            withoutContent = True


        ret = self.modelsClass.listbypage(pagesize,pagenum,keywords,
                                           withoutContent,onlypublish=True)

        return JR(ret)

    def listbypage_allstate(self,request):
        pagesize = request.pd.get('pagesize')
        pagenum = request.pd.get('pagenum')
        keywords = request.pd.get('keywords')

        ret = self.modelsClass.listbypage(pagesize,pagenum,keywords)

        return JR(ret)

    def getone(self,request):
        oid = request.pd.get('id')
        ret = self.modelsClass.getone(oid)

        return JR(ret)

    def addone(self,request):
        data = request.pd.get('data')
        ret = self.modelsClass.addone(data,request.user.id)

        return JR(ret)

    def modifyone(self,request):
        oid = request.pd.get('id')
        newdata = request.pd.get('newdata')
        ret = self.modelsClass.modifyone(oid,newdata)

        return JR(ret)

    def banone(self,request):
        oid = request.pd.get('id')
        ret = self.modelsClass.banone(oid)

        return JR(ret)

    def publishone(self,request):
        oid = request.pd.get('id')
        ret = self.modelsClass.publishone(oid)

        return JR(ret)

    def deleteone(self,request):
        oid = request.pd.get('id')
        ret = self.modelsClass.deleteone(oid)

        return JR(ret)

    def holdone(self,request):
        authorid = request.user.id
        oid = request.pd.get('id')
        ret = self.modelsClass.holdone(oid,authorid)

        return JR(ret)


class NoticeHandle(ArticleHandle):
    modelsClass = Notice

    @BaseRequestHandle.admin_required
    def listbypage_allstate(self,request):
        return super().listbypage_allstate(request)

    @BaseRequestHandle.admin_required
    def getone(self,request):
        return super().getone(request)

    @BaseRequestHandle.admin_required
    def addone(self,request):
        return super().addone(request)

    @BaseRequestHandle.admin_required
    def modifyone(self,request):
        return super().modifyone(request)

    @BaseRequestHandle.admin_required
    def banone(self,request):
        return super().banone(request)

    @BaseRequestHandle.admin_required
    def publishone(self,request):
        return super().publishone(request)

    @BaseRequestHandle.admin_required
    def deleteone(self,request):
        return super().deleteone(request)

class NewsHandle(ArticleHandle):
    modelsClass = News

    @BaseRequestHandle.admin_required
    def listbypage_allstate(self, request):
        return super().listbypage_allstate(request)

    @BaseRequestHandle.admin_required
    def getone(self, request):
        return super().getone(request)

    @BaseRequestHandle.admin_required
    def addone(self, request):
        return super().addone(request)

    @BaseRequestHandle.admin_required
    def modifyone(self, request):
        return super().modifyone(request)

    @BaseRequestHandle.admin_required
    def banone(self, request):
        return super().banone(request)

    @BaseRequestHandle.admin_required
    def publishone(self, request):
        return super().publishone(request)

    @BaseRequestHandle.admin_required
    def deleteone(self, request):
        return super().deleteone(request)

class PaperHandle(ArticleHandle):
    modelsClass = Paper
    def __init__(self):
        super().__init__()
        self.action_table['listminebypage'] = self.listminebypage
        self.action_table['holdone'] = self.holdone

    @BaseRequestHandle.login_required
    def handle(self,request):
        return super().handle(request)


    def listminebypage(self,request):
        pagesize = request.pd.get('pagesize')
        pagenum = request.pd.get('pagenum')
        keywords = request.pd.get('keywords')

        authorid = request.user.id

        ret = self.modelsClass.listbypage(pagesize,pagenum,keywords,
                    withoutContent=False,onlypublish=False,authorid=authorid)

        return JR(ret)

    def modifyone(self,request):
        authorid = request.user.id

        oid = request.pd.get('id')
        newdata = request.pd.get('newdata')
        ret = self.modelsClass.modifyone(oid, newdata,authorid)

        return JR(ret)

    @BaseRequestHandle.admin_required
    def banone(self, request):
        return super().banone(request)


    def publishone(self,request):
        oid = request.pd.get('id')
        authorid = request.user.id
        usertype = request.session['usertype']

        ret = self.modelsClass.publishone(oid,usertype,authorid)

        return JR(ret)

    def deleteone(self,request):
        oid = request.pd.get('id')
        authorid = request.user.id
        usertype = request.session['usertype']

        ret = self.modelsClass.deleteone(oid,usertype,authorid)

        return JR(ret)

class ConfigHandle(BaseRequestHandle):
    def __init__(self):
        self.action_table = {
            'set':self.setconfig,
            'get':self.getconfig,
            'gethomepagebyconfig':self.gethomepagebyconfig
        }

    @BaseRequestHandle.admin_required
    def setconfig(self,request):
        name = request.pd.get('name')
        value = request.pd.get('value')

        ret = Config.setconfig(name,value)
        return JR(ret)

    @BaseRequestHandle.admin_required
    def getconfig(self,request):
        name = request.pd.get('name')

        ret = Config.getconfig(name)
        return JR(ret)

    def gethomepagebyconfig(self,request):

        try:
            value = Config.objects.get(name='homepage').value
        except:
            retInfo = {'news':[],'notice':[],'paper':[]}
            Config.objects.create(name='homepage',
                                  value=json.dumps(retInfo))

            return JR({'ret':0,'info':retInfo})

        homeCfg = json.loads(value)

        info = {}
        for model,article_type in [(News,'news'),(Notice,'notice'),(Paper,'paper')]:

            idlist = homeCfg[article_type]
            if idlist:
                ret = model.getmany(idlist)
                NewItems = []
                for oid in idlist:
                    for item in ret:
                        if item['id'] == oid:
                            NewItems.append(item)
                            ret.remove(item)
                            break

                info[article_type] = NewItems
            else:
                info[article_type] = []

        return JR({'ret':0,'info':info})


class EtcHandle(BaseRequestHandle):
    def __init__(self):
        self.action_table = {
            'getmyprofile':self.getmyprofile,
            'setmyprofile':self.setmyprofile,
            'listteachers':self.listteachers,
            'thumbuporcancel':self.thumbuporcancel,
        }

    @BaseRequestHandle.StuTea_required
    def getmyprofile(self,request):
        oid = request.user.id
        usertype = request.user.usertype
        ret = User.getmyprofile(oid)
        if ret['ret'] != 0:
            return JR(ret)

        if usertype == 2000:
            ret_teacher = TSRelation.gerteacher(oid)

            ret['profile']['teacher'] = ret_teacher

        # ret = {'ret':0,'profile':ret1}

        return JR(ret)

    @BaseRequestHandle.StuTea_required
    def setmyprofile(self,request):
        oid = request.user.id
        newdata = request.pd['newdata']
        try:
            if 'teacherid' in newdata:
                teacherid = newdata.pop('teacherid')
                ret1 = TSRelation.setrelation(oid, teacherid)

                if ret1['ret'] != 0:
                    return JR(ret1)

            with transaction.atomic():
                ret2 = User.modifyone(oid,newdata)

                if ret2['ret'] != 0:
                    return JR(ret2)

            return JR({'ret':0})

        except:
            err = traceback.format_exc()
            return JR({'ret':1,'msg':err})

    @BaseRequestHandle.student_required
    def listteachers(self,request):
        keywords = request.pd.get('keywords')

        ret = User.listbypage(30,1,keywords,usertype=3000)

        return JR(ret)

    @BaseRequestHandle.login_required
    def thumbuporcancel(self,request):
        userid = request.user.id
        paperid = request.pd.get('paperid')

        ret = ThumbupOrCancel.thumbuporcancel(userid,paperid)

        return JR(ret)


class WF_Handle(BaseRequestHandle):

    PEMISSION_STUDENT = 1  # 任何学生
    PEMISSION_TEACHER = 2  # 任何老师
    PEMISSION_CREATOR = 3  # 工作流创建者
    PEMISSION_TEACHER_OF_CREATOR = 4  # 工作流创建者的老师

    def __init__(self):
        self.action_table = {
            'listbypage':self.listbypage,
            'getone':self.getone,
            'stepaction':self.stepaction,
            'getstepactiondata':self.getstepactiondata
        }


    def _permisson_check_ok(self,userid,usertype,whocan,wf):
        if whocan == self.PEMISSION_STUDENT:
            if usertype == 2000:
                return True
            else:
                return False


        if whocan == self.PEMISSION_TEACHER:
            if usertype == 3000:
                return True
            else:
                return False


        if whocan == self.PEMISSION_CREATOR:
            if wf is None:
                return False
            if wf.creator_id == userid:
                return True
            else:
                return False

        if whocan == self.PEMISSION_TEACHER_OF_CREATOR:

            if wf is None:
                return False

            if userid == wf.creator_id:
                return False

            teacher = TSRelation.gerteacher(wf.creator_id)
            if userid != teacher['id']:
                return False
            else:
                return True

        return True

    def whatICanDo(self,userid,usertype,wf,actions):
        whaticando = []
        for key, action in actions.items():
            whocan = action['whocan']

            check_res = self._permisson_check_ok(userid, usertype, whocan, wf)
            if check_res:
                whaticando.append(action)

        return whaticando

    @BaseRequestHandle.login_required
    def listbypage(self,request):
        usertype= request.user.usertype
        pagesize = request.pd.get('pagesize')
        pagenum = request.pd.get('pagenum')
        keywords = request.pd.get('keywords')

        creators = False

        if usertype == 2000:
            creators = [request.user.id]
        if usertype == 3000:
            qs = TSRelation.objects.filter(teacher_id=request.user.id).values().order_by('id')
            qs_list = list(qs)
            creators = []

            for i in qs_list:
                creators.append(i['student_id'])

        ret = self.WF_DataMgr_MODEL.listbypage(pagesize,pagenum,keywords,creators)
        return JR(ret)

    def getone(self, request):
        wf_id = int(request.pd.get('wf_id'))
        withwhatcanido = request.pd.get('withwhatcanido')

        if wf_id == -1:
            ret = self.WF_RULL_START
            return JR(ret)

        ret = self.WF_DataMgr_MODEL.getone(wf_id)
        wf = ret.pop('wf')

        if withwhatcanido:
            userid = request.user.id
            usertype = request.user.usertype

            currentstate = ret['rec']['currentstate']

            if currentstate not in self.WF_RULL:
                return None
            if currentstate == '评分结束':
                ret['whaticando'] = None
                return JR(ret)

            actions = self.WF_RULL[currentstate]['actions']
            whaticando = self.whatICanDo(userid,usertype,wf,actions)

            ret['whaticando'] = whaticando

        return JR(ret)

    def getTitle(self,submitdata):
        for data in submitdata:
            if data['name'] == '毕业设计标题':
                title = data['value']
                break
        return title

    def stepaction(self,request):
        actionKey = request.pd.get('key')
        wf_id = int(request.pd.get('wf_id'))
        submitdata = request.pd.get('submitdata')

        if wf_id == -1:
            wf = None
            wf_state = '开始'
        else:
            wf = self.WF_MODEL.objects.filter(id=wf_id).first()
            if wf is None:
                return JR({'ret': 2, 'msg': '工作流记录不存在'})

            wf_state = wf.currentstate

            if self.WF_RULL[wf_state] == None:
                return JR({'ret': 1, 'whaticando': None})


        permittedActions = self.WF_RULL[wf_state]['actions']

        if actionKey not in permittedActions:
            return JR({
                'ret': 3,
                'msg': f'当前状态：{wf_state}，不支持动作：{actionKey} '})

        whocan = permittedActions[actionKey]['whocan']

        if not self._permisson_check_ok(request.session['userid'],
                                        request.session['usertype'],
                                        whocan,
                                        wf):
            return JR({
                'ret': 3,
                'msg': '无权进行此操作'})


        action = permittedActions[actionKey]
        uid = request.session['userid']

        if wf_state == '开始':
            title = self.getTitle(submitdata)
            wf = self.WF_DataMgr_MODEL.create(uid,
                                              title,
                                              action['name'],
                                              json.dumps(submitdata,ensure_ascii=False),
                                              action['next'])

        else:
            title = None
            if wf_state == '主题被驳回':
                title = self.getTitle(submitdata)

            self.WF_DataMgr_MODEL.update(wf_id,
                                         uid,
                                         title,
                                         action['name'],
                                         json.dumps(submitdata,ensure_ascii=False),
                                         action['next'])

        return JR({"ret": 0, "wf_id": wf.id})

    @BaseRequestHandle.login_required
    def getstepactiondata(self,request):
        step_id = request.pd.get('step_id')

        ret = self.WF_DataMgr_MODEL.getstepactiondata(step_id)

        return JR(ret)


class WF_Design_Handle(WF_Handle):
    WF_MODEL = WF_Design
    WFStep_MODEL = WF_Design_STEP

    WF_DataMgr_MODEL = WF_Design_DataMgr

    WF_RULL_START = {
                    "ret": 0,
                    "rec": {
                        "id": -1,
                        "creatorname": "",
                        "title": "",
                        "currentstate": "",
                        "createdate": ""
                    },
                    "whaticando": [
                        {
                            "name": "创建主题",
                            "submitdata": [
                                {
                                    "name": "毕业设计标题",
                                    "type": "text",
                                    "check_string_len": [
                                        1,
                                        50
                                    ]
                                },
                                {
                                    "name": "主题描述",
                                    "type": "richtext",
                                    "check_string_len": [
                                        10,
                                        10000
                                    ]
                                }
                            ],
                            "whocan": 1,
                            "next": "主题已创建",
                            "key": "create_topic"
                        }
                    ]
                }

    WF_RULL = {
        # 状态名，开始状态名一定要是初识
        "开始": {
            # action 定义了该状态下，可以接受的 几种 操作
            # 如果action == None，表示该状态为 结束状态
            "actions": {
                # 创建主题, key 名为  create_topic
                'create_topic': {
                    'name':  '创建主题',
                    # 该动作需要提交的数据格式
                    'submitdata': [
                        {
                            'name': '毕业设计标题',  # 字段名称
                            'type': 'text',  # 字段类型
                            'check_string_len': [1, 50],  # 字段输入值长度要求
                        },
                        {
                            'name': '主题描述',
                            'type': 'richtext',
                            'check_string_len': [10, 10000],  # 字段输入值长度要求
                        },
                    ],
                    # 谁可以执行该动作
                    'whocan': WF_Handle.PEMISSION_STUDENT,
                    # 操作后，进入到 下一个状态名
                    'next': "主题已创建",
                    'key': 'create_topic',
                },
            }
        },

        # 状态名
        "主题已创建": {
            "actions": {
                # 下面的两个操作都是该学生对应的老师做的
                'reject_topic': {
                    'name': '驳回主题',
                    'submitdata': [
                        {
                            'name': '驳回原因',
                            'type': 'textarea',
                            'check_string_len': [0, 10000],  # 字段输入值长度要求
                        },
                    ],
                    'whocan': WF_Handle.PEMISSION_TEACHER_OF_CREATOR,
                    'next': "主题被驳回",
                    'key': 'reject_topic',
                },
                'approve_topic': {
                    'name': '批准主题',
                    'submitdata': [
                        {
                            'name': '备注',
                            'type': 'richtext',
                            'check_string_len': [0, 10000],  # 字段输入值长度要求
                        },
                    ],
                    'whocan': WF_Handle.PEMISSION_TEACHER_OF_CREATOR,
                    'next': "主题已通过",
                    'key': 'approve_topic',
                },
            }
        },

        # 状态名
        "主题被驳回": {
            "actions": {
                # 学生修改主题
                'modify_topic': {
                    'name': '修改主题',
                    'submitdata': [
                        {
                            'name': '毕业设计标题',
                            'type': 'text',
                            'check_string_len': [2, 100],  # 字段输入值长度要求
                        },
                        {
                            'name': '主题描述',
                            'type': 'richtext',
                            'check_string_len': [20, 10000],  # 字段输入值长度要求
                        },
                    ],
                    'whocan': WF_Handle.PEMISSION_CREATOR,
                    'next': "主题已创建",
                    'key': 'modify_topic',
                },
            }
        },

        # 状态名
        "主题已通过": {
            "actions": {
                # 学生提交毕业设计
                'submit_design': {
                    'name': '提交毕业设计',
                    'submitdata': [
                        {
                            'name': '毕业设计内容',
                            'type': 'richtext',
                            'check_string_len': [20, 50000],  # 字段输入值长度要求
                        },
                    ],
                    'whocan': WF_Handle.PEMISSION_CREATOR,
                    'next': "学生已提交毕业设计",
                    'key': 'submit_design',
                },
            }
        },

        # 状态名
        "学生已提交毕业设计": {
            "actions": {
                # 下面的操作都是该学生对应的老师做的
                'score_design': {
                    'name': '评分',
                    'submitdata': [
                        {
                            'name': '得分',
                            'type': 'int',
                            'check_int_range': [0, 100]  # 数字取值范围检查
                        },
                        {
                            'name': '备注',
                            'type': 'richtext',
                            'check_string_len': [20, 10000],  # 字段输入值长度要求
                        },
                    ],
                    'whocan': WF_Handle.PEMISSION_TEACHER_OF_CREATOR,
                    'next': '评分结束',
                    'key': 'score_design',
                },
                'reject': {
                    'name': '打回重做',
                    'submitdata': [
                        {
                            'name': '驳回原因',
                            'type': 'richtext',
                            'check_string_len': [20, 10000],  # 字段输入值长度要求
                        },
                    ],
                    'whocan': WF_Handle.PEMISSION_TEACHER_OF_CREATOR,
                    'next': '主题已通过',
                    'key': 'reject',
                },
            }
        },

        # 为None表示这是流程结束步骤，没有操作了
        "评分结束": None
    }



























